﻿// Inner Fire 游戏引擎库
// 简单的MESH
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 用于读取简单的模型
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-01-18

#include "dx_mesh.h"
#include <dx/core/dx_exception.h>
#include <dx/core/dx_utils.h>
#include <dx/mesh/render_item.h>
#include <graphics/vertex.h>
#include <klog.h>

namespace ifire::dx {
DxSubmesh DxSubmesh::EMPTY{};

///////////////////////////////////////////////////////////////////////////////
// DxSubmesh
///////////////////////////////////////////////////////////////////////////////

void DxSubmesh::SetRenderObject(RenderItem* item) const {
  item->geo = parent;
  item->primitive_type = D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  item->index_count = index_count;
  item->index_start = index_start;
  item->vertex_start = vertex_start;
}

///////////////////////////////////////////////////////////////////////////////
// DxMesh
///////////////////////////////////////////////////////////////////////////////

DxMesh::DxMesh(int index, ikit::sstr name) : DxElement(index, name) {}

void DxMesh::CreateResource(ID3D12Device* device,
    ID3D12GraphicsCommandList* cmd_list, const DxMeshCreateDesc& desc) {
  const UINT vbByteSize = (UINT)desc.VertexSize * desc.VertexStrideSize;
  const UINT ibByteSize = (UINT)desc.IndexSize * desc.IndexStrideSize;

  HASSERT(D3DCreateBlob(vbByteSize, &vertex_buffer_cpu));
  CopyMemory(VertexCpuBuffer(), desc.pVertexData, vbByteSize);

  HASSERT(D3DCreateBlob(ibByteSize, &index_buffer_cpu));
  CopyMemory(IndexCpuBuffer(), desc.pIndexData, ibByteSize);

  vertex_buffer_gpu = DxUtils::CreateDefaultBuffer(
      device, cmd_list, desc.pVertexData, vbByteSize, vertex_buffer_uploader);

  index_buffer_gpu = DxUtils::CreateDefaultBuffer(
      device, cmd_list, desc.pIndexData, ibByteSize, index_buffer_uploader);

  vertex_byte_stride = desc.VertexStrideSize;
  vertex_buffer_byte_size = vbByteSize;
  index_format = desc.IndexFormat;
  index_buffer_byte_size = ibByteSize;
}

DxSubmesh& DxMesh::GetSubMesh(ikit::sstr name) {
  if (name.empty()){
    return submeshs_[0];
  }
  for (auto& e : submeshs_) {
    if (e.name == name) {
      return e;
    }
  }
  KERROR("Unable find submesh: %s", name.c_str());
  return submeshs_[0];
}

DxSubmesh& DxMesh::AddSubmesh(ikit::sstr name, UINT material_index,
    UINT start_index_location, UINT index_count, UINT base_vertex_location,
    UINT vertex_count) {
  return submeshs_.emplace_back(this, name, material_index,
      start_index_location, index_count, base_vertex_location, vertex_count);
}

const DxSubmesh& DxMesh::DefaultSubmesh() const { return submeshs_[0]; }

D3D12_VERTEX_BUFFER_VIEW DxMesh::VertexBufferView() const {
  D3D12_VERTEX_BUFFER_VIEW view = {};
  view.BufferLocation = vertex_buffer_gpu->GetGPUVirtualAddress();
  view.StrideInBytes = vertex_byte_stride;
  view.SizeInBytes = vertex_buffer_byte_size;
  return view;
}

D3D12_INDEX_BUFFER_VIEW DxMesh::IndexBufferView() const {
  D3D12_INDEX_BUFFER_VIEW view = {};
  view.BufferLocation = index_buffer_gpu->GetGPUVirtualAddress();
  view.Format = index_format;
  view.SizeInBytes = index_buffer_byte_size;
  return view;
}

// 等待数据上传之后，就可以释放这些内存。
void DxMesh::DisposeUploaders() {
  vertex_buffer_uploader = nullptr;
  index_buffer_uploader = nullptr;
}

//void DxMesh::CreateStandardQuad(
//    ID3D12Device* device, ID3D12GraphicsCommandList* cmd_list) {
//  // 此项目的顶点
//  eastl::vector<UIVertex> vertices = {{
//      {XMFLOAT2(-1.0f, -1.0f), XMFLOAT2(0.0f, 0.0f)}, // 左下角
//      {XMFLOAT2(1.0f, -1.0f), XMFLOAT2(1.0f, 0.0f)},  // 右下角
//      {XMFLOAT2(1.0f, 1.0f), XMFLOAT2(1.0f, 1.0f)},   // 右上角
//      {XMFLOAT2(-1.0f, 1.0f), XMFLOAT2(0.0f, 1.0f)}   // 左上角
//  }};
//  // 此项目的索引
//  eastl::vector<std::uint16_t> indices = {0, 1, 2, 0, 2, 3};
//
//  // 将顶点和索引建立为缓冲区
//  dx::DxMeshCreateDesc create_desc{};
//  create_desc.pVertexData = vertices.data();
//  create_desc.pIndexData = indices.data();
//  create_desc.VertexSize = static_cast<UINT>(vertices.size());
//  create_desc.VertexStrideSize = sizeof(Vertex);
//  create_desc.IndexSize = static_cast<UINT>(indices.size());
//  create_desc.IndexFormat = DXGI_FORMAT_R16_UINT;
//  create_desc.IndexStrideSize = sizeof(std::uint16_t);
//  CreateResource(device, cmd_list, create_desc);
//}

} // namespace ifire::dx
